const express = require('express');
const { chromium } = require('playwright');
const fs = require('fs');
const path = require('path');
const axios = require('axios');
const os = require('os'); // 添加os模块用于获取网络接口信息

const app = express();
const port = 3000;

// 获取服务器IP地址的函数
function getServerIp() {
  const interfaces = os.networkInterfaces();
  let serverIp = 'localhost';
  let fallbackIp = 'localhost'; 
  // 遍历所有网络接口
  Object.keys(interfaces).forEach((interfaceName) => {
    interfaces[interfaceName].forEach((iface) => {
      // 跳过内部IP和非IPv4地址
      if (iface.family === 'IPv4' && !iface.internal) {
        // 优先选择192.168开头的IP地址
        if (iface.address.startsWith('192.168')) {
          serverIp = iface.address;
        } else {
          // 保存其他非内部IPv4地址作为备选
          fallbackIp = iface.address;
        }
      }
    });
  }); 
  // 如果找到了192.168开头的IP地址，返回它，否则返回其他非内部IPv4地址
  return serverIp !== 'localhost' ? serverIp : fallbackIp;
}

// 获取服务器IP地址
const serverIp = getServerIp();
// 构建基础URL
const baseURL = `http://${serverIp}:${port}`;

// 中间件设置
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// 静态文件服务
app.use('/static', express.static(path.join(__dirname, 'public')));
// 添加output目录的静态文件服务
app.use('/static/images', express.static(path.join(__dirname, 'output')));

// 确保输出目录存在
const outputDir = path.join(__dirname, 'output');
if (!fs.existsSync(outputDir)) {
  fs.mkdirSync(outputDir, { recursive: true });
}

// 模拟题目数据库 - 使用从API返回的数据格式
const questionDatabase = { };

//简道云请求题目数据
async function fetchQuestionFromJiandaoyun(questionId) {
  try {
    const response = await axios({
      url: "https://api.jiandaoyun.com/api/v5/app/entry/data/list",
      method: "POST",
      headers: {
        "Authorization": "Bearer ODZBplgegfy98JPfxtrZBRAEdVTB1xGw",
        "Content-Type": "application/json"
      },
      data: {
        "app_id": "632eba7e35faf20008ef9e45",
        "data_id": "",
        "entry_id": "63f31de7a7d95b000873d000",
        "fields": [],
        "filter": {
          "cond": [
            {
              "field": "question_id",
              "method": "eq",
              "type": "text",
              "value": [
                questionId
              ]
            }
          ],
          "rel": "and"
        },
        "limit": 1
      }
    }); 
    // 检查响应数据
    if (response.data && response.data.data && Array.isArray(response.data.data) && response.data.data.length > 0) {
      return response.data.data[0];
    } else {
      console.log('简道云API返回数据为空或格式不正确:', response.data);
      return null;
    }
  } catch (error) {
    console.error('从简道云获取题目数据失败:', error.message);
    return null;
  }
}
 
// API接口：根据题目ID生成图片
app.get('/api/generate-image/:questionId', async (req, res) => {
  try {
    const questionId = req.params.questionId;
    // console.log('正在生成题目ID为', questionId, '的图片...');
    // 首先尝试从简道云获取题目数据
    let question = await fetchQuestionFromJiandaoyun(questionId);
    // console.log('从简道云获取的题目数据:', question);
    // 如果从简道云获取失败，则尝试从本地数据库获取 
    if (!question) {
        return res.status(404).json({ error: '题目不存在' });
      }  
    // 生成题目图片
    const imagePath = await generateImage(question, questionId); 
    // 生成解析图片
    const parseImagePath = await generateParseImage(question, questionId);
    
    // 返回图片URL或直接发送图片
    res.json({
      code:1,
      success: true,
      imageUrl: `${baseURL}/static/images/${questionId}.png`,
      parseImageUrl: `${baseURL}/static/images/${questionId}_parse.png`,
      downloadUrl: `${baseURL}/api/download-image/${questionId}`,
      downloadParseUrl: `${baseURL}/api/download-parse-image/${questionId}`
    });
  } catch (error) {
    console.error('生成图片时出错:', error);
    res.status(500).json({ code:-1, error: '生成图片失败' });
  }
});

// 新增API接口：接收JSON数据并生成图片
app.post('/api/generate-image-from-json', async (req, res) => { 
  try {
    // 解析请求体中的JSON数据
    const requestData = req.body;
    
    // 检查是否有body字段
    if (!requestData) {
      return res.status(400).json({ error: '请求格式不正确，缺少body字段' });
    }
    
    // 直接使用请求体中的JSON数据
    let jsonData = requestData;
    // 如果requestData是字符串，尝试解析它
    if (typeof requestData === 'string') {
      try {
        jsonData = JSON.parse(requestData);
      } catch (e) {
        return res.status(400).json({ error: '无法解析JSON数据' });
      }
    } 
      
    // 获取第一个题目数据
    const questionData = jsonData;
    
    // 检查必要字段是否存在
    if (!questionData.question_content || !questionData.question_parse || !questionData.option_lists) {
      return res.status(400).json({ error: '题目数据不完整，缺少必要字段' });
    }
    
    // 生成唯一的题目ID（使用时间戳）
    const questionId = Date.now().toString();
    
    // 生成题目图片
    const imagePath = await generateImage(questionData, questionId);
    
    // 生成解析图片
    const parseImagePath = await generateParseImage(questionData, questionId);
    
    // 返回图片URL或直接发送图片
    res.json({
      code:1,
      success: true,
      questionId: questionId,
      imageUrl: `${baseURL}/static/images/${questionId}.png`,
      parseImageUrl: `${baseURL}/static/images/${questionId}_parse.png`,
      downloadUrl: `${baseURL}/api/download-image/${questionId}`,
      downloadParseUrl: `${baseURL}/api/download-parse-image/${questionId}`
    });
  } catch (error) {
    console.error('处理JSON数据生成图片时出错:', error);
    res.status(500).json({ error: '生成图片失败' });
  }
});

// 下载题目图片接口
app.get('/api/download-image/:questionId', (req, res) => {
  const questionId = req.params.questionId;
  const imagePath = path.join(outputDir, `${questionId}.png`);
  
  if (fs.existsSync(imagePath)) {
    res.download(imagePath, `question-${questionId}.png`, (err) => {
      if (err) {
        console.error('下载题目图片时出错:', err);
        return;
      }
      
      // 设置2分钟后删除图片
      setTimeout(() => {
        if (fs.existsSync(imagePath)) {
          fs.unlink(imagePath, (unlinkErr) => {
            if (unlinkErr) {
              console.error('删除题目图片时出错:', unlinkErr);
            } else {
              console.log(`题目图片已删除: ${imagePath}`);
            }
          });
        }
      }, 2 * 60 * 1000); // 2分钟 = 2 * 60 * 1000毫秒
    });
  } else {
    res.status(404).json({ error: '图片不存在' });
  }
});

// 下载解析图片接口
app.get('/api/download-parse-image/:questionId', (req, res) => {
  const questionId = req.params.questionId;
  const imagePath = path.join(outputDir, `${questionId}_parse.png`); 
  if (fs.existsSync(imagePath)) {
    res.download(imagePath, `parse-${questionId}.png`, (err) => {
      if (err) {
        console.error('下载解析图片时出错:', err);
        return;
      }
      
      // 设置2分钟后删除图片
      setTimeout(() => {
        if (fs.existsSync(imagePath)) {
          fs.unlink(imagePath, (unlinkErr) => {
            if (unlinkErr) {
              console.error('删除解析图片时出错:', unlinkErr);
            } else {
              console.log(`解析图片已删除: ${imagePath}`);
            }
          });
        }
      }, 2 * 60 * 1000); // 2分钟 = 2 * 60 * 1000毫秒
    });
  } else {
    res.status(404).json({ error: '解析图片不存在' });
  }
});

// 根据文本长度确定使用的CSS类
function getTextSizeClass(text, optionLists) {
  // 计算问题文本的长度
  let totalLength = text.length;
  
  // 如果有选项，计算所有选项的总长度
  if (optionLists && Array.isArray(optionLists) && optionLists.length > 0) {
    optionLists.forEach(option => {
      if (option.option_joint) {
        totalLength += option.option_joint.length;
      }
    });
  }
  console.log(`Total length of text and options: ${totalLength}`);

  // 更精细的文字大小调整逻辑
  if (totalLength <= 20) {
    return 'long-text-20';
  } else if (totalLength <= 30) {
    return 'long-text-30';
  } else if (totalLength <= 40) {
    return 'long-text-40';
  } else if (totalLength <= 50) {
    return 'long-text-50';
  } else if (totalLength <= 70) {
    return 'long-text-70';
  } else if (totalLength <= 80) {
    return 'long-text-80';
  } else if (totalLength <= 90) {
    return 'long-text-90';
  } else if (totalLength <= 100) {
    return 'long-text-100';
  } else if (totalLength <= 150) {
    return 'long-text-150';
  } else if (totalLength <= 200) {
    return 'long-text-200';
  } else if (totalLength <= 300) {
    return 'long-text-300';
  } else if (totalLength <= 400) {
    return 'long-text-400';
  } else {
    return 'long-text-end';
  }
} 

// 使用Playwright生成题目图片的函数
async function generateImage(question, questionId) {
  const browser = await chromium.launch();
  const page = await browser.newPage();
  
  // 设置视口大小为1080x1440
  await page.setViewportSize({ width: 1080, height: 1440 });
  
  // 加载HTML模板
  const templatePath = path.join(__dirname, 'templates', 'question-template.html');
  let templateHtml = fs.readFileSync(templatePath, 'utf8');
  
  // 修复图片路径问题 - 将图片转换为Base64数据URL
  const titleImagePath = path.join(__dirname, 'templates', 'question-title.png');
  const titleImageData = fs.readFileSync(titleImagePath);
  const titleImageBase64 = `data:image/png;base64,${titleImageData.toString('base64')}`; 
  templateHtml = templateHtml.replace('{{question_title}}', titleImageBase64);
  
  // 根据问题文本和选项总字数确定使用的CSS类
  const textSizeClass = getTextSizeClass(question.question_content, []);
  
  // 替换模板中的变量
  const html = templateHtml 
    .replace('{{question_text}}', question.question_content)
    .replace('{{text_size_class}}', textSizeClass)
    .replace('{{options}}', formatOptions(question.option_lists));
  
  // 设置页面内容
  await page.setContent(html, { waitUntil: 'networkidle' });
  
  // 截图 - 使用固定尺寸1080x1440
  const imagePath = path.join(outputDir, `${questionId}.png`);
  await page.screenshot({ path: imagePath, clip: { x: 0, y: 0, width: 1080, height: 1440 } });
  
  await browser.close();
  return imagePath;
}
 // 使用Playwright生成解析图片的函数
async function generateParseImage(question, questionId) {
  const browser = await chromium.launch();
  const page = await browser.newPage();
  // 设置视口大小为1080x1440
  await page.setViewportSize({ width: 1080, height: 1440 });
  // 加载HTML模板
  const templatePath = path.join(__dirname, 'templates', 'parse-template.html');
  let templateHtml = fs.readFileSync(templatePath, 'utf8');
  // 分别计算问题和解析的字体class
  const questionTextSizeClass = getTextSizeClass(question.question_content || '', []);
  const explanationTextSizeClass = getTextSizeClass(question.question_parse || '', []);
  // 准备模板变量数据
  const questionText = question.question_content || '';
  // 根据correct_answer找到对应的选项内容
  let correctAnswerText = '';
  if (question.correct_answer && question.option_lists && Array.isArray(question.option_lists)) {
    const correctOption = question.option_lists.find(option => option.question_option === question.correct_answer);
    if (correctOption) {
      const optionContent = correctOption.option_content || (correctOption.option_joint ? correctOption.option_joint : '');
      correctAnswerText = `${question.correct_answer}. ${optionContent}`;
    } else {
      correctAnswerText = question.correct_answer + '.' + (question.question_option || '');
    }
  } else {
    correctAnswerText = question.correct_answer ? (question.correct_answer + '.' + (question.question_option || '')) : '';
  }
  const explanationText = question.question_parse ? '    ' + question.question_parse : '';
  // 替换模板中的变量，分别传递两个class
  const html = templateHtml
    .replace('{{question_text_size_class}}', questionTextSizeClass)
    .replace('{{explanation_text_size_class}}', explanationTextSizeClass)
    .replace('{{question_text}}', questionText)
    .replace('{{correct_answer}}', correctAnswerText)
    .replace('{{explanation_text}}', explanationText || '');
  await page.setContent(html, { waitUntil: 'networkidle' });
  const imagePath = path.join(outputDir, `${questionId}_parse.png`);
  await page.screenshot({ path: imagePath, clip: { x: 0, y: 0, width: 1080, height: 1440 } });
  await browser.close();
  return imagePath;
}

// 格式化选项的辅助函数 - 适配新的数据结构
function formatOptions(optionLists) {
  // 如果没有选项列表或选项列表为空，返回默认选项
  if (!optionLists || !Array.isArray(optionLists) || optionLists.length === 0) {
    return `<div class="option">
                <div class="option-label">A</div>
                <div class="option-text">选项A</div>
            </div>
            <div class="option">
                <div class="option-label">B</div>
                <div class="option-text">选项B</div>
            </div>
            <div class="option">
                <div class="option-label">C</div>
                <div class="option-text">选项C</div>
            </div>
            <div class="option">
                <div class="option-label">D</div>
                <div class="option-text">选项D</div>
            </div>`;
  }
  
  // 先遍历所有选项，找出最长的文本长度
  let maxContentLength = 0;
  optionLists.forEach(option => {
    const optionContent = option.option_content || (option.option_joint ? option.option_joint : '选项内容');
    const contentLength = optionContent.length;
    if (contentLength > maxContentLength) {
      maxContentLength = contentLength;
    }
  });
  
  // 根据最长选项内容确定统一的CSS类
  let uniformTextSizeClass = '';
  if (maxContentLength <= 10) {
    uniformTextSizeClass = 'long-option-text-10';
  } else if (maxContentLength <= 20) {
    uniformTextSizeClass = 'long-option-text-20';
  } else if (maxContentLength <= 30) {
    uniformTextSizeClass = 'long-option-text-30';
  } else if (maxContentLength <= 40) {
    uniformTextSizeClass = 'long-option-text-40';
  } else {
    uniformTextSizeClass = 'long-option-text-50';
  }
  
  // 使用question_option和option_content字段生成选项HTML，所有选项使用相同的CSS类
  return optionLists.map((option, index) => {
    // 如果没有question_option字段，使用默认的选项标签（A, B, C, D...）
    const optionLabel = option.question_option || String.fromCharCode(65 + index); // 65是ASCII码中的'A'
    // 如果没有option_content字段但有option_joint字段，使用option_joint
    const optionContent = option.option_content || (option.option_joint ? option.option_joint : '选项内容');
    
    return `<div class="option">
                <div class="option-label">${optionLabel}</div>
                <div class="option-text ${uniformTextSizeClass}">${optionContent}</div>
            </div>`;
  }).join('\n            ');
}

// 启动服务器
app.listen(port, () => {
  console.log(`服务器运行在 http://${serverIp}:${port}`);
  console.log(`API示例: http://${serverIp}:${port}/api/generate-image/1`);
  console.log(`新API: POST http://${serverIp}:${port}/api/generate-image-from-json`);
  console.log(`题目图片下载: http://${serverIp}:${port}/api/download-image/:questionId`);
  console.log(`解析图片下载: http://${serverIp}:${port}/api/download-parse-image/:questionId`);
});

// 清空 output 目录下所有文件的函数
function clearOutputDir() {
  const files = fs.readdirSync(outputDir);
  files.forEach(file => {
    const filePath = path.join(outputDir, file);
    if (fs.existsSync(filePath) && fs.lstatSync(filePath).isFile()) {
      fs.unlinkSync(filePath);
    }
  });
}

// 新增GET接口，支持GET方式清空output目录
app.get('/api/clear-output', (req, res) => {
  try {
    clearOutputDir();
    res.json({ success: true, message: 'output 目录已清空' });
  } catch (error) {
    res.status(500).json({ success: false, error: '清空 output 目录失败' });
  }
});